目標:
管理員可以在商品清單的後台,編輯與刪除商品
class _MyAppState extends State<MyApp> {
List<Map<String, dynamic>> _products = [];
...
void _updateProduct(int index, Map<String, dynamic> product) {
setState(() {
_products[index] = product;
});
}
void _deleteProduct(int index) {
setState(() {
_products.removeAt(index);
});
}
@override
Widget build(BuildContext context) {
return MaterialApp(
...
routes: {
...
'/admin': (BuildContext context) =>
ProductsAdminPage(_addProduct, _updateProduct, _deleteProduct, _products),
},
...
);
}
}
...
class ProductsAdminPage extends StatelessWidget {
final Function addProduct;
final Function updateProduct;
final Function deleteProduct;
final List<Map<String, dynamic>> products;
ProductsAdminPage(this.addProduct, this.updateProduct, this.deleteProduct, this.products);
....
@override
Widget build(BuildContext context) {
return DefaultTabController(
length: 2,
child: Scaffold(
...
appBar: AppBar(...),
body: TabBarView(
children: <Widget>[
ProductEditPage(addProduct: addProduct),
ProductListPage(products, updateProduct, deleteProduct)
],
),
),
);
}
}
...
class ProductEditPage extends StatefulWidget {
final Function addProduct;
final Function updateProduct;
final Map<String, dynamic> product;
final int productIndex;
ProductEditPage({this.addProduct, this.updateProduct, this.product, this.productIndex});
@override
State<StatefulWidget> createState() {
return _ProductEditPageState();
}
}
class _ProductEditPageState extends State<ProductEditPage> {
final Map<String, dynamic> _formData = {
'title': null,
'description': null,
'price': null,
'image': 'assets/food.jpg'
};
final GlobalKey<FormState> _formKey = GlobalKey<FormState>();
final _titleFocusNode = FocusNode();
final _descriptionFocusNode = FocusNode();
final _priceFocusNode = FocusNode();
Widget _buildTitleTextField() {
return EnsureVisibleWhenFocused(
focusNode: _titleFocusNode,
child: TextFormField(
...
initialValue: widget.product == null ? '' : widget.product['title'],
validator: (String value) {...},
onSaved: (String value) {
_formData['title'] = value;
},
),
);
}
Widget _buildDescriptionTextField() {
return EnsureVisibleWhenFocused(
focusNode: _descriptionFocusNode,
child: TextFormField(
...
decoration: InputDecoration(labelText: 'Product Description'),
initialValue: widget.product == null ? '' : widget.product['description'],
validator: (String value) {...},
onSaved: (String value) {
_formData['description'] = value;
},
),
);
}
Widget _buildPriceTextField() {
return EnsureVisibleWhenFocused(
focusNode: _priceFocusNode,
child: TextFormField(
...
decoration: InputDecoration(labelText: 'Product Price'),
initialValue: widget.product == null ? '' : widget.product['price'].toString(),
validator: (String value) {...},
onSaved: (String value) {
_formData['price'] = double.parse(value);
},
),
);
}
Widget _buildPageContent(BuildContext context) {
...
return GestureDetector(
...
child: Container(
margin: EdgeInsets.all(10.0),
child: Form(
key: _formKey,
child: ListView(
...
children: <Widget>[
_buildTitleTextField(),
_buildDescriptionTextField(),
_buildPriceTextField(),
...
RaisedButton(
child: Text('Save'),
textColor: Colors.white,
onPressed: _submitForm,
)
],
),
),
),
);
}
void _submitForm() {
if (!_formKey.currentState.validate()) {
return;
}
_formKey.currentState.save();
if (widget.product == null) {
widget.addProduct(_formData);
} else {
widget.updateProduct(widget.productIndex, _formData);
}
Navigator.pushReplacementNamed(context, '/products');
}
@override
Widget build(BuildContext context) {
final Widget pageContent = _buildPageContent(context);
return widget.product == null
? pageContent
: Scaffold(
appBar: AppBar(
title: Text('Edit Product'),
),
body: pageContent,
);
}
}
import './product_edit.dart';
class ProductListPage extends StatelessWidget {
final Function updateProduct;
final Function deleteProduct;
final List<Map<String, dynamic>> products;
ProductListPage(this.products, this.updateProduct, this.deleteProduct);
Widget _buildEditButton(BuildContext context, int index) {
return IconButton(
icon: Icon(Icons.edit),
onPressed: () {
Navigator.of(context).push(
MaterialPageRoute(
builder: (BuildContext context) {
return ProductEditPage(
//直接把product_edit.dart的內容推到route裡面
product: products[index],
updateProduct: updateProduct,
productIndex: index,
);
},
),
);
},
);
}
@override
Widget build(BuildContext context) {
return ListView.builder(
itemBuilder: (BuildContext context, int index) {
return Dismissible(
//整個list的項目都是可以拉掉的
key: Key(products[index]['title']),
onDismissed: (DismissDirection direction) {
if (direction == DismissDirection.endToStart) {
//從右到左的方向
deleteProduct(index);
}
},
background: Container(color: Colors.red),
//底下的背景是紅色比較像刪除
child: Column(
children: <Widget>[
ListTile(
//左圖片右敘述加小標的排列
leading: CircleAvatar(
backgroundImage: AssetImage(products[index]['image']),
//圓形的商品圖片
),
title: Text(products[index]['title']),
subtitle: Text('$${products[index]['price'].toString()}'),
//小標放入價格
trailing: _buildEditButton(context, index),
//右邊的東西
),
Divider()
//與下一個list item的分隔線
],
),
);
},
itemCount: products.length,
);
}
}